package nf.util.swing;

import javax.swing.SwingUtilities;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.Executor;

public abstract class AsynchronusTask<T, V> implements Runnable
{
	private Set<PropertyChangeListener> listeners;
	private Executor executor;
	private List<V> published;
	private AtomicReference<T> finalResult;
	
	public AsynchronusTask()
	{
		this(new ThreadExecutor());
	}
	
	public AsynchronusTask(Executor executor)
	{
		this.executor = executor;
		this.listeners = new HashSet<PropertyChangeListener>();
		this.published = new LinkedList<V>();
	}
	
	protected abstract T doInBackground();
	
	public void execute()
	{
		executor.execute(this);
	}
	
	public void run()
	{
		doInBackground();
	}
	
	protected final void publish(V... chunks)
	{
		synchronized (published) {
			for (V chunk : chunks) {
				published.add(chunk);
			}
			
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					synchronized (published) {
						if (published.size() <= 0)
							return;
						List<V> copiedChunks = new ArrayList<V>(published);
						published.clear();
						process(copiedChunks);
					}
				}
			});
		}
	}
	
	protected void process(List<V> chunks)
	{
		// do nothing by default
	}
	
	private static class ThreadExecutor implements Executor
	{
		public void execute(Runnable task)
		{
			new Thread(task).start();
		}
	}
}
